package org.rambadger.command;

import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.databind.introspect.VisibilityChecker;
import com.sun.jersey.api.core.ResourceConfig;
import com.yammer.dropwizard.Service;
import com.yammer.dropwizard.config.Bootstrap;
import com.yammer.dropwizard.config.Environment;
import com.yammer.dropwizard.views.ViewBundle;
import com.yammer.dropwizard.assets.AssetsBundle;
import org.rambadger.command.auth.CookieAuthProvider;
import org.rambadger.command.axon.AxonBundle;
import org.rambadger.command.axon.MongoBundle;
import org.rambadger.command.providers.ConfigProvider;
import org.rambadger.command.providers.PaginationProvider;
import org.rambadger.command.providers.UploadHelperProvider;
import org.rambadger.command.resource.*;
import org.rambadger.command.validation.ValidationExceptionMapper;

import javax.ws.rs.core.MediaType;
import java.util.Map;

/**
 * CBW: Write me.
 *
 * @author Chris Wash <a href="mailto:chris.wash@gmail.com">chris.wash@gmail.com</a>
 */
public class CommandServices extends Service<CommandConfiguration> {
    private final MongoBundle mongo;
    private final AxonBundle axon;

    public CommandServices() {
        this.mongo = new MongoBundle();
        this.axon = new AxonBundle(mongo);
    }

    @Override
    public void initialize(Bootstrap<CommandConfiguration> commandConfigurationBootstrap) {
        commandConfigurationBootstrap.setName("commandBus");
        commandConfigurationBootstrap.addBundle(mongo);
        commandConfigurationBootstrap.addBundle(axon);
        commandConfigurationBootstrap.addCommand(new ConfigureAdminsCommand(this, mongo, axon));
        commandConfigurationBootstrap.addCommand(new RebuildViewsCommand(this, axon));
        commandConfigurationBootstrap.addBundle(new ViewBundle());
        commandConfigurationBootstrap.addBundle(new AssetsBundle("/assets/", "/static"));
    }

    @Override
    public void run(CommandConfiguration commandConfiguration, Environment environment) throws Exception {
        /*
        This should only apply to the output from resources (and certainly not the injected JacksonDBCollections).
        The purpose is to hide internal properties (like the password hash) from the public JSON.
        To allow a property to be visible in the output, it has to be annotated with @JsonProperty.
         */
        environment.getObjectMapperFactory().setVisibilityChecker(new VisibilityChecker.Std(JsonAutoDetect.Visibility.NONE));
        /*
        Alternately, we could disable MapperFeature.DEFAULT_VIEW_INCLUSION and apply @JsonView annotations to both the properties and the resource.
        As a shortcut make a new annotation and apply both @JsonView and @JacksonAnnotationsInside to it.
         */

        ResourceConfig resourceConfig = environment.getJerseyResourceConfig();
        Map<String, MediaType> typeMappings = resourceConfig.getMediaTypeMappings();
        typeMappings.put("json", MediaType.APPLICATION_JSON_TYPE);
        typeMappings.put("html", MediaType.TEXT_HTML_TYPE);
        typeMappings.put("txt", MediaType.TEXT_PLAIN_TYPE);
        typeMappings.put("rss", MediaType.APPLICATION_XML_TYPE);
        typeMappings.put("xml", MediaType.APPLICATION_XML_TYPE);
        typeMappings.put("zip", new MediaType("application", "zip"));
        //Perhaps other things like XML/JS/CSS? If we need types not already defined by MediaType we should make a MediaType subclass to hold them.

        environment.addTask(new RebuildTask(axon));
        environment.addTask(new AlterAdminTask(axon));

        environment.addProvider(com.sun.jersey.multipart.impl.MultiPartConfigProvider.class);
        environment.addProvider(com.sun.jersey.multipart.impl.FormDataMultiPartDispatchProvider.class);
        environment.addProvider(com.sun.jersey.multipart.impl.MultiPartReaderServerSide.class);

        environment.addProvider(new ConfigProvider(commandConfiguration));
        environment.addProvider(CookieAuthProvider.class);
        environment.addProvider(PaginationProvider.class);
        environment.addProvider(UploadHelperProvider.class);

        environment.addProvider(ValidationExceptionMapper.class);

        environment.addResource(LoginResource.class);
        environment.addResource(LogoutResource.class);

        environment.addResource(IndexResource.class);

        environment.addResource(RegisterUserResource.class);
        environment.addResource(RegisterPlatformResource.class);
        environment.addResource(RegisterTrackResource.class);
        environment.addResource(RegisterAssignmentResource.class);

        environment.addResource(ViewMustacheTest.class);
        environment.addResource(ViewUserResource.class);
        environment.addResource(ViewUsersResource.class);
        environment.addResource(ViewPlatformResource.class);
        environment.addResource(ViewPlatformsResource.class);

        environment.addResource(AdminResource.class);

        environment.addResource(TestRSSResource.class);
        environment.addResource(DynamicDownloadsResource.class);
    }
}

